# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: xguo
import datetime
import pytz

from coin.exchange.base.kr_rest.public_client_base import PublicClientBase
from coin.exchange.okex_futures_swap.kr_rest.native_public_client import OkexSwapNativePublicClient

import dateutil.parser

from coin.exchange.okex_futures.kr_rest.futures_product import OkexFuturesProduct
from coin.proto.coin_market_query_pb2 import (
    ProductTicker,
    ExchangeTicker,
    ProductKlineElement,
    ProductKline,
)


def parse_native_timestamp(native_timestamp):
  # native_timestamp looks like 2018-11-20T06:00:19.864Z
  timestamp = dateutil.parser.parse(native_timestamp).timestamp() * 1e+9
  return int(timestamp)


class OkexSwapFuturesFeedParser(object):
  @staticmethod
  def parse_native_ticker(ticker, product):
    """Sample ticker response:
    {
      "instrument_id": "XRP-USD-SWAP",
      "last": "0.3009",
      "high_24h": "0.3076",
      "low_24h": "0.296",
      "volume_24h": "625403",
      "best_ask": "0.301",
      "best_bid": "0.3009",
      "timestamp": "2019-02-11T03:32:20.259Z"
    }
    """
    assert ticker['instrument_id'] == product.native_symbol_v3

    return ProductTicker(
        high=float(ticker['high_24h']),
        low=float(ticker['low_24h']),
        last=float(ticker['last']),
        ask=float(ticker['best_ask']),
        bid=float(ticker['best_bid']),
        volume_24hr=float(ticker['volume_24h']),  # Last rolling 24 hours.
        exchange_timestamp=parse_native_timestamp(ticker['timestamp']),
        native_symbol=product.native_symbol,
        symbol=product.symbol)

  @staticmethod
  def parse_exchange_ticker(update_msg):
    product_ticker_list = []
    for ticker in update_msg:
      instrument_id = ticker['instrument_id']
      product = OkexFuturesProduct.FromStrNativeProductNothrow(instrument_id)
      if product is None:
        continue
      product_ticker = OkexSwapFuturesFeedParser.parse_native_ticker(ticker, product)
      product_ticker_list.append(product_ticker)

    return ExchangeTicker(exchange='Okex', each_ticker=product_ticker_list)

  @staticmethod
  def parse_native_kline(update_msg, product, kline_period):
    klines = update_msg
    kline_group = []
    for kline in klines:
      kline_dt = datetime.datetime.strptime(kline[0], '%Y-%m-%dT%H:%M:%S.%fZ')
      kline_ts = kline_dt.replace(tzinfo=pytz.UTC).timestamp() * 1e+9
      if product.quote.currency == 'USDT':
        turnover = float(kline[6]) * float(kline[4])
      else:
        turnover = float(kline[6])
      product_kline = ProductKlineElement(kline_timestamp=int(kline_ts),
                                          open=float(kline[1]),
                                          high=float(kline[2]),
                                          low=float(kline[3]),
                                          close=float(kline[4]),
                                          volume=float(kline[5]),
                                          turnover=turnover)
      kline_group.append(product_kline)
    return ProductKline(
        symbol=product.symbol,
        native_symbol=product.native_symbol,
        exchange='Okex',
        market_type='Futures',
        kline_period=str(kline_period),
        klines=kline_group,
    )


class OkexSwapFuturesPublicClient(PublicClientBase):
  ProductType = OkexFuturesProduct

  def __init__(self, timeout=10):
    self.npubc = OkexSwapNativePublicClient(timeout=timeout)

  def query_ticker_impl(self, product):
    symbol = product.native_symbol
    update = self.npubc.get_ticker(symbol)
    update.msg = OkexSwapFuturesFeedParser.parse_native_ticker(update.msg, product)
    return update

  def query_exchange_ticker_impl(self):
    update = self.npubc.get_exchange_ticker()
    update.msg = OkexSwapFuturesFeedParser.parse_exchange_ticker(update.msg)
    return update

  def query_history_kline_impl(self, product, kline_period, start_time, end_time):
    symbol = product.native_symbol
    update = self.npubc.get_history_kline(symbol, kline_period, start_time, end_time)
    update.msg = OkexSwapFuturesFeedParser.parse_native_kline(update.msg, product, kline_period)
    return update

  def query_level_book_impl(self, product):
    raise NotImplementedError()
